use std::fs::File;
use std::io::{Write, Read};
use std::path::Path;
use anyhow::{Result, Context};
use log::{debug, info, warn};
use yaml_rust::{YamlEmitter, Yaml, yaml, YamlLoader};
use std::collections::HashSet;

use crate::project::Project;

/// clangd配置生成器
pub struct ClangdConfig {
    pub include_paths: Vec<String>,
    pub defines: Vec<String>,
    pub cpp_standard: String,
    pub qt_dir: Option<String>,
    // 自定义配置项
    pub suppressed_diagnostics: HashSet<String>,
    pub clang_tidy_add: Vec<String>,
    pub clang_tidy_remove: HashSet<String>,
}

impl Default for ClangdConfig {
    fn default() -> Self {
        let mut suppressed_diagnostics = HashSet::new();
        suppressed_diagnostics.insert("fuchsia-default-arguments-calls".to_string());
        suppressed_diagnostics.insert("readability-include".to_string());
        suppressed_diagnostics.insert("libc-namespace-namespace".to_string());
        
        let mut clang_tidy_remove = HashSet::new();
        clang_tidy_remove.insert("fuchsia-default-arguments-calls".to_string());
        clang_tidy_remove.insert("llvm-include-order".to_string());
        clang_tidy_remove.insert("llvmlibc-*".to_string());
        
        Self {
            include_paths: Vec::new(),
            defines: Vec::new(),
            cpp_standard: "c++17".to_string(),
            qt_dir: None,
            suppressed_diagnostics,
            clang_tidy_add: vec!["*".to_string()],
            clang_tidy_remove,
        }
    }
}

impl ClangdConfig {
    /// 从项目列表生成配置
    pub fn from_projects(projects: &[&Project], qt_dir: Option<&String>) -> Self {
        let mut config = ClangdConfig::default();
        
        // 收集所有包含目录
        let mut include_paths = std::collections::HashSet::new();
        
        // 收集所有项目的包含目录
        for project in projects {
            for (_, dirs) in &project.include_directories {
                for dir in dirs {
                    include_paths.insert(format!("-I{}", dir));
                }
            }
        }
        
        // 添加Qt路径（如果提供）
        if let Some(qt_dir) = qt_dir {
            config.add_qt_paths(qt_dir, &mut include_paths);
        }
        
        // 收集所有预处理器定义
        let mut defines = std::collections::HashSet::new();
        for project in projects {
            for (_, defs) in &project.preprocessor_defs {
                for def in defs {
                    if !def.is_empty() {
                        defines.insert(format!("-D{}", def));
                    }
                }
            }
        }
        
        // 添加Windows常用定义
        defines.insert("-DWIN32".to_string());
        defines.insert("-D_WINDOWS".to_string());
        defines.insert("-DUNICODE".to_string());
        defines.insert("-D_UNICODE".to_string());
        
        config.include_paths = include_paths.into_iter().collect();
        config.include_paths.sort();
        
        config.defines = defines.into_iter().collect();
        config.defines.sort();
        
        // 保存Qt目录
        config.qt_dir = qt_dir.cloned();
        
        config
    }
    
    /// 添加Qt路径
    fn add_qt_paths(&self, qt_dir: &str, include_paths: &mut std::collections::HashSet<String>) {
        let qt_base = qt_dir.replace('\\', "/");
        
        // Qt主要包含目录
        include_paths.insert(format!("-I{}/include", qt_base));
        include_paths.insert(format!("-I{}/include/QtCore", qt_base));
        include_paths.insert(format!("-I{}/include/QtGui", qt_base));
        include_paths.insert(format!("-I{}/include/QtWidgets", qt_base));
        include_paths.insert(format!("-I{}/include/QtNetwork", qt_base));
        include_paths.insert(format!("-I{}/include/QtOpenGL", qt_base));
        include_paths.insert(format!("-I{}/include/QtSql", qt_base));
        include_paths.insert(format!("-I{}/include/QtXml", qt_base));
        include_paths.insert(format!("-I{}/include/QtConcurrent", qt_base));
        include_paths.insert(format!("-I{}/include/QtTest", qt_base));
        include_paths.insert(format!("-I{}/include/QtPrintSupport", qt_base));
        
        // 添加C++17标准
        include_paths.insert("-std=c++17".to_string());
        
        // 添加Qt预处理器定义
        include_paths.insert("-DQT_CORE_LIB".to_string());
        include_paths.insert("-DQT_GUI_LIB".to_string());
        include_paths.insert("-DQT_WIDGETS_LIB".to_string());
    }
    
    /// 从模板文件加载配置
    pub fn load_template(&mut self, template_path: &Path) -> Result<()> {
        info!("从模板加载clangd配置: {}", template_path.display());
        
        // 读取模板文件内容
        let mut file = File::open(template_path)
            .with_context(|| format!("无法打开clangd模板文件: {}", template_path.display()))?;
        let mut content = String::new();
        file.read_to_string(&mut content)
            .with_context(|| format!("无法读取clangd模板文件: {}", template_path.display()))?;
        
        // 解析YAML
        let docs = YamlLoader::load_from_str(&content)
            .with_context(|| format!("解析模板文件YAML失败: {}", template_path.display()))?;
        
        if docs.is_empty() {
            warn!("模板文件为空或格式无效: {}", template_path.display());
            return Ok(());
        }
        
        let doc = &docs[0];
        
        // 处理Diagnostics.Suppress部分
        if let Some(diagnostics) = doc["Diagnostics"].as_hash() {
            if let Some(suppress) = diagnostics.get(&Yaml::String("Suppress".to_string())) {
                if let Some(items) = suppress.as_vec() {
                    // 清空默认值，使用模板中提供的值
                    self.suppressed_diagnostics.clear();
                    for item in items {
                        if let Some(s) = item.as_str() {
                            self.suppressed_diagnostics.insert(s.to_string());
                        }
                    }
                    debug!("从模板加载了 {} 个诊断忽略项", self.suppressed_diagnostics.len());
                }
            }
            
            // 处理ClangTidy部分
            if let Some(clang_tidy) = diagnostics.get(&Yaml::String("ClangTidy".to_string())) {
                if let Some(tidy) = clang_tidy.as_hash() {
                    // 处理Add部分
                    if let Some(add) = tidy.get(&Yaml::String("Add".to_string())) {
                        if let Some(items) = add.as_vec() {
                            // 清空默认值，使用模板中提供的值
                            self.clang_tidy_add.clear();
                            for item in items {
                                if let Some(s) = item.as_str() {
                                    self.clang_tidy_add.push(s.to_string());
                                }
                            }
                            debug!("从模板加载了 {} 个ClangTidy添加项", self.clang_tidy_add.len());
                        }
                    }
                    
                    // 处理Remove部分
                    if let Some(remove) = tidy.get(&Yaml::String("Remove".to_string())) {
                        if let Some(items) = remove.as_vec() {
                            // 清空默认值，使用模板中提供的值
                            self.clang_tidy_remove.clear();
                            for item in items {
                                if let Some(s) = item.as_str() {
                                    self.clang_tidy_remove.insert(s.to_string());
                                }
                            }
                            debug!("从模板加载了 {} 个ClangTidy排除项", self.clang_tidy_remove.len());
                        }
                    }
                }
            }
        }
        
        info!("成功加载clangd模板配置");
        Ok(())
    }

    /// 生成.clangd配置文件
    pub fn generate_clangd_file(&self, output_dir: &Path) -> Result<()> {
        info!("生成 .clangd 配置文件");
        
        // 准备YAML数据
        let mut compile_flags_add = Vec::new();
        
        // 添加包含路径
        for path in &self.include_paths {
            compile_flags_add.push(Yaml::String(path.clone()));
        }
        
        // 添加预处理器定义
        for define in &self.defines {
            compile_flags_add.push(Yaml::String(define.clone()));
        }
        
        // 添加C++标准
        compile_flags_add.push(Yaml::String(format!("-std={}", self.cpp_standard)));
        
        // 构建YAML文档
        let mut root = yaml::Hash::new();
        
        // CompileFlags 部分
        let mut compile_flags = yaml::Hash::new();
        compile_flags.insert(Yaml::String("Add".to_string()), Yaml::Array(compile_flags_add));
        root.insert(Yaml::String("CompileFlags".to_string()), Yaml::Hash(compile_flags));
        
        // Diagnostics 部分
        let mut diagnostics = yaml::Hash::new();
        
        // Suppress 数组
        let mut suppress = Vec::new();
        for item in &self.suppressed_diagnostics {
            suppress.push(Yaml::String(item.clone()));
        }
        diagnostics.insert(Yaml::String("Suppress".to_string()), Yaml::Array(suppress));
        
        // ClangTidy 部分
        let mut clang_tidy = yaml::Hash::new();
        
        // ClangTidy.Add
        let mut add_array = Vec::new();
        for item in &self.clang_tidy_add {
            add_array.push(Yaml::String(item.clone()));
        }
        clang_tidy.insert(Yaml::String("Add".to_string()), Yaml::Array(add_array));
        
        // ClangTidy.Remove
        let mut remove_array = Vec::new();
        for item in &self.clang_tidy_remove {
            remove_array.push(Yaml::String(item.clone()));
        }
        clang_tidy.insert(Yaml::String("Remove".to_string()), Yaml::Array(remove_array));
        
        // 将ClangTidy添加到Diagnostics
        diagnostics.insert(Yaml::String("ClangTidy".to_string()), Yaml::Hash(clang_tidy));
        
        // 将Diagnostics添加到根
        root.insert(Yaml::String("Diagnostics".to_string()), Yaml::Hash(diagnostics));
        
        // Index 部分
        let mut index = yaml::Hash::new();
        index.insert(Yaml::String("Background".to_string()), Yaml::String("Build".to_string()));
        root.insert(Yaml::String("Index".to_string()), Yaml::Hash(index));
        
        // 将YAML转换为字符串
        let yaml_doc = Yaml::Hash(root);
        let mut yaml_string = String::new();
        {
            let mut emitter = YamlEmitter::new(&mut yaml_string);
            emitter.dump(&yaml_doc).unwrap();
        }
        
        // 去掉YAML文档开头的 "---\n"
        if yaml_string.starts_with("---\n") {
            yaml_string = yaml_string[4..].to_string();
        }
        
        // 创建并写入文件
        let clangd_path = output_dir.join(".clangd");
        let mut file = File::create(&clangd_path)?;
        file.write_all(yaml_string.as_bytes())?;
        
        info!("成功生成 .clangd 配置文件: {}", clangd_path.display());
        debug!("配置内容:\n{}", yaml_string);
        
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_clangd_config_default() {
        let config = ClangdConfig::default();
        assert_eq!(config.cpp_standard, "c++17");
        assert!(config.include_paths.is_empty());
        assert!(config.defines.is_empty());
    }
    
    #[test]
    fn test_from_projects_empty() {
        let projects = vec![];
        let config = ClangdConfig::from_projects(&projects, None);
        
        // 应该包含基本的Windows定义
        assert!(config.defines.contains(&"-DWIN32".to_string()));
        assert!(config.defines.contains(&"-D_WINDOWS".to_string()));
    }
} 